//
// server.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include <iostream>
#include <string>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <list>
#include "protocol.h"



using boost::asio::ip::udp;

// These are the conencted clients
std::list<udp::endpoint*> clients;

/*
 * Send *msg to *receiver
 */
void send_message_to(int * msg, udp::endpoint * receiver, udp::socket *socket){
    socket->send_to(
            boost::asio::buffer((void*)msg, sizeof(int)),
            *receiver
    );
}

/*
 * This is a safe way to send a message, data is disposed after message
 * is sent. Is there a better way to do this? Can we avoid the copying?
 */
void send_wrapped_message_to(int msg, udp::endpoint * receiver, udp::socket *socket){
    int * pMsg = (int*)malloc(sizeof(int));
    *pMsg = msg;
    send_message_to(pMsg, receiver, socket);
    delete(pMsg);
}

/* 
 * Here we will 'accept' the connection by adding it to a list of clients.
 * If the connector sends an invalid greeting, we will not accept it, this
 * is because we could potentially accept completely bogus connections, such
 * as streaming media.
 */
void accept_connection(udp::socket *socket){
    udp::endpoint *client = (udp::endpoint*)malloc(sizeof(udp::endpoint));
    boost::system::error_code error;
    int *recv_buf;
    recv_buf = (int *)malloc(sizeof(int));

    // Receive a potential greeting
    socket->receive_from(
        boost::asio::buffer((void*)recv_buf, sizeof(int)), // Here we drop the msg
        *client // This is our connecting client
    );

    // Check if the greeting is correct
    if(*recv_buf == VALID_GREETING){ /* Accept this connection */
        std::cout << "Valid connection found\n";
        // Add this client to the clients list
        clients.push_back(client);
        std::cout << "Client added to 'clients list'\n";
        send_wrapped_message_to(GREETING_RESPONSE, client, socket);
    }
    else{
        std::cout << "INVALID connection dropped!\n";
    }
}


/*
 * Broadcast an arbitrary message to all clients in the list
 * supplied. The message is a 32bit integer.
 */
void broadcast_message(int * msg, std::list<udp::endpoint *>  *clients, udp::socket * socket){
    boost::system::error_code ignored_error;
    for (std::list<udp::endpoint *>::iterator it = clients->begin(); it != clients->end(); it++){
        send_message_to(msg, *it, socket); // **it is endpoint
        std::cout << "Issued broadcast\n";
        }
}

int main()
{
        boost::asio::io_service io_service;

        udp::socket socket(io_service, udp::endpoint(udp::v4(), 3419));

        for (;;)
        {
            
            // Accept the connection
            accept_connection(&socket);
            std::cout << "Read data\n";

            int msg;
            msg = PING;
            broadcast_message(&msg, &clients, &socket);

/*
            if (error && error != boost::asio::error::message_size)
                throw boost::system::system_error(error);

            //std::string message = make_daytime_string();
            int * primitiveMessage;
            primitiveMessage = (int*) malloc(sizeof(int));
            *primitiveMessage = 0xFFF & 0x0F0;

            boost::system::error_code ignored_error;
            socket.send_to(boost::asio::buffer((void*)primitiveMessage, sizeof(int)),
                    remote_endpoint, 0, ignored_error);*/
        }

    return 0;
}

